package com.optitronics.beans;

import java.util.List;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.Table;
import javax.persistence.TableGenerator;
import javax.persistence.Version;
import javax.validation.constraints.NotNull;

import org.hibernate.annotations.Formula;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.transaction.annotation.Transactional;

import com.optitronics.util.OptitronicsConstants;

@Entity
@Table(name = "clients")
@Configurable
public class Client {

	@PersistenceContext
	transient EntityManager entityManager;

	@Id
	@TableGenerator(name = "clientGenerator", pkColumnValue = "CLIENTS", table = OptitronicsConstants.COUNTER_TABLE_NAME, pkColumnName = OptitronicsConstants.COUNTER_PK_COLUMN_NAME, valueColumnName = OptitronicsConstants.COUNTER_VALUE_COLUMN_NAME, allocationSize = OptitronicsConstants.COUNTER_ALLOCATION_SIZE)
	@GeneratedValue(strategy = GenerationType.TABLE, generator = "clientGenerator")
	@Column(name = "ID")
	private Integer id;

	@Version
	@Column(name = "VERSION")
	private Integer version;

	@Column(name = "NAME")
	@NotNull
	private String name;

	@Column(name = "EMAIL")
	@NotNull
	private String email;

	@Column(name = "CITY")
	@NotNull
	private String city;

	@Column(name = "ADDRESS")
	@NotNull
	private String address;

	@Column(name = "CONTACT_PERSON")
	private String contactPerson;

	@Column(name = "PHONE")
	private String phone;

	@Formula(" ( SELECT COUNT(*) FROM order_items oi WHERE oi.BUYER_ID = ID ) ")
	private Integer orderCount;

	@Transactional
	public void persist() {
		if (this.entityManager == null)
			this.entityManager = entityManager();
		this.entityManager.persist(this);
	}

	@Transactional
	public void flush() {
		if (this.entityManager == null)
			this.entityManager = entityManager();
		this.entityManager.flush();
	}

	@Transactional
	public void clear() {
		if (this.entityManager == null)
			this.entityManager = entityManager();
		this.entityManager.clear();
	}

	public static final EntityManager entityManager() {
		EntityManager em = new Client().entityManager;
		if (em == null)
			throw new IllegalStateException(
					"Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
		return em;
	}

	@SuppressWarnings("unchecked")
	public static Client findClientByNameAndEmail(String name, String email) {
		String queryString = "SELECT c FROM Client c WHERE lower(c.name) = :name AND lower(c.email) = :email";
		Query query = entityManager().createQuery(queryString).setParameter("name", name.toLowerCase())
				.setParameter("email", email.toLowerCase());
		List<Client> results = query.getResultList();

		return results.isEmpty() ? null : results.get(0);
	}

	public static long countClients() {
		return entityManager().createQuery("select count(o) from Client o", Long.class).getSingleResult();
	}

	public static List<Client> findAllClients() {
		return entityManager().createQuery("select o from Client o ORDER BY o.name", Client.class).getResultList();
	}

	public static Client findClient(Integer id) {
		if (id == null)
			return null;
		return entityManager().find(Client.class, id);
	}

	public static List<Client> findClientsEntries(int firstResult, int maxResults) {
		return entityManager().createQuery("select o from Client o ORDER BY o.name", Client.class)
				.setFirstResult(firstResult).setMaxResults(maxResults).getResultList();
	}

	public String getName() {
		return this.name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getEmail() {
		return this.email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public String getCity() {
		return this.city;
	}

	public void setCity(String city) {
		this.city = city;
	}

	public String getAddress() {
		return this.address;
	}

	public void setAddress(String address) {
		this.address = address;
	}

	public String getContactPerson() {
		return this.contactPerson;
	}

	public void setContactPerson(String contactPerson) {
		this.contactPerson = contactPerson;
	}

	public String getPhone() {
		return this.phone;
	}

	public void setPhone(String phone) {
		this.phone = phone;
	}

	public Integer getId() {
		return this.id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public Integer getVersion() {
		return this.version;
	}

	public void setVersion(Integer version) {
		this.version = version;
	}

	public Integer getOrderCount() {
		return orderCount;
	}

	public void setOrderCount(Integer orderCount) {
		this.orderCount = orderCount;
	}
}
